package cn.iocoder.yudao.framework.common.util.reflect;

import cn.hutool.core.util.ObjectUtil;
import jakarta.annotation.Nonnull;
import lombok.experimental.UtilityClass;
import lombok.extern.slf4j.Slf4j;
import org.springframework.aop.framework.AopProxyUtils;
import org.springframework.core.ResolvableType;

import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

/**
 * <pre>
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 *  反射工具类
 * OOoO0OOoO0OOOooo0oOOOO0OOOOO0oooOO0ooOOO0Ooooo0OOOOo0ooooO0OOooo0Ooooo0OOOOO
 * </pre>
 *
 * @author 山野羡民（1032694760@qq.com）
 * @since 2025/04/07
 * @see cn.hutool.core.util.ReflectUtil
 * @see org.springframework.util.ReflectionUtils
 * @see io.swagger.v3.core.util.ReflectionUtils
 * @see com.fhs.core.trans.util.ReflectUtils
 */
@Slf4j
@UtilityClass
public class ReflectUtils {

    /**
     * 获取字段的真实类型（集合取泛型参数）
     */
    public static Class<?> getFieldActualType(Class<?> clazz, String fieldName) {
        Field field = org.springframework.util.ReflectionUtils.findField(clazz, fieldName);
        if (field == null) {
            log.warn("class {} 中无字段 {}", clazz.getName(), fieldName);
            return null;
        }
        return getFieldActualType(field);
    }

    /**
     * 获取字段的真实类型（集合取泛型参数）
     */
    public static Class<?> getFieldActualType(Field field) {
        Type genericType = field.getGenericType();
        if (genericType instanceof Class) {
            return (Class<?>) genericType;
        }
        // 得到泛型里的class类型对象
        else if (genericType instanceof ParameterizedType pt) {
            return (Class<?>) pt.getActualTypeArguments()[0];
        } else {
            log.warn("非预期的GenericType : {}", genericType.getTypeName());
            return null;
        }
    }

    public static Class<?> getGenericityClass(Object instance, int index) {
        Class<?> hostClass = getTargetClass(instance);
        ResolvableType resolvableType = ResolvableType.forClass(hostClass);
        if (resolvableType.getSuperType().getType().getTypeName().equals(Object.class.getName()) && ObjectUtil.isNotEmpty(resolvableType.getInterfaces())) {
            resolvableType = resolvableType.getInterfaces()[0];
        } else {
            resolvableType = resolvableType.getSuperType();
            ResolvableType[] types = resolvableType.getGenerics();
            // 逐级向上找父类
            if (ObjectUtil.isEmpty(types) || index >= types.length) {
                resolvableType = resolvableType.getSuperType();
                types = resolvableType.getGenerics();
                if (ObjectUtil.isEmpty(types) || index >= types.length) {
                    resolvableType = resolvableType.getSuperType();
                }
            }
        }
        ResolvableType[] types = resolvableType.getGenerics();
        if (ObjectUtil.isEmpty(types) || index >= types.length) {
            types = resolvableType.getSuperType().getGenerics();
        }
        if (ObjectUtil.isNotEmpty(types) && types.length > index) {
            return types[index].resolve();
        }
        log.debug("无法从 {} 类定义中获取第 {} 个泛型类", hostClass.getName(), index);
        return null;
    }

    public static Class<?> getTargetClass(Object instance) {
        return (instance instanceof Class) ? (Class<?>) instance : AopProxyUtils.ultimateTargetClass(instance);
    }

    /**
     * 获取类所有属性（包含父类中属性）
     */
    @Nonnull
    public static List<Field> extractAllFields(Class<?> clazz) {
        return extractClassFields(clazz, true, null);
    }

    /**
     * 获取类所有属性（包含父类中属性）
     */
    @Nonnull
    public static List<Field> extractAllFields(Class<?> clazz, boolean excludeSpecial) {
        return extractClassFields(clazz, excludeSpecial, null);
    }

    /**
     * 获取类所有属性（包含父类中属性）
     */
    @Nonnull
    public static List<Field> extractFields(Class<?> clazz, Class<? extends Annotation> annotation) {
        return extractClassFields(clazz, false, annotation);
    }

    @Nonnull
    private static List<Field> extractClassFields(Class<?> beanClazz, boolean excludeStaticFinal, Class<? extends Annotation> annotation) {
        List<Field> fieldList = new ArrayList<>();
        Set<String> fieldNameSet = new HashSet<>();
        loopFindFields(beanClazz, excludeStaticFinal, annotation, fieldList, fieldNameSet);
        return fieldList;
    }

    private static void loopFindFields(Class<?> beanClazz, boolean excludeSpecial, Class<? extends Annotation> annotation, List<Field> fieldList, Set<String> fieldNameSet) {
        if (beanClazz == null) {
            return;
        }
        Field[] fields = beanClazz.getDeclaredFields();
        for (Field field : fields) {
            // 被重写属性，以子类的为准
            if (!fieldNameSet.add(field.getName())) {
                continue;
            }
            if (excludeSpecial) {
                // 忽略 static、final、transient
                int modifiers = field.getModifiers();
                if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers) || Modifier.isTransient(modifiers)) {
                    continue;
                }
            }
            if (annotation == null || field.getAnnotation(annotation) != null) {
                fieldList.add(field);
            }
        }
        loopFindFields(beanClazz.getSuperclass(), excludeSpecial, annotation, fieldList, fieldNameSet);
    }

}
